/*
 * edb_type.c - EnCluster Base DB type-related definitions
 * Clunix, cezanne@clunix.com, 2005.2
 *
 * Copyright (c) 2001-2008 by Clunix Inc. All Rights Reserved.
 */
#include "config.h"

#include "edb_p.h"

srt_t	ST_EDBFIELD;
srt_t	ST_ATTR_UPDATE;
srt_t	ST_ATTR_FETCH;
srt_t	ST_ATTR_SYSTEM;
srt_t	ST_RUN;
srt_t	ST_STATUS;
srt_t	ST_MODE;
srt_t	ST_TIME;
srt_t	ST_XID;
srt_t	ST_OWNER;
srt_t	ST_PATH;
srt_t	ST_FILE;
srt_t	ST_MFILE;
srt_t	ST_DIMAGE;
srt_t	ST_PERM;

static const char *edb_fields[] = {
	"name", "type", "val", "owner", "attr_update", "reactor", NULL
};

static const char *attr_update[] = {
	"none", "private", "shared", "instant", NULL
};

static const char *attr_fetch[] = {
	"none", "normal", "ondemand", "instant", NULL
};

static const char *attr_system[] = {
	"normal", "modifiable", "volatile", NULL
};

static const char *runs[] = {
	"stop", "start", "restart", "pause", NULL
};

static const char *status[] = {
	"unknown", "down", "up", "partial", "paused",
	"suspend", "goingdown", "goingup",
	"repairing", "recovering", "recovered", NULL
};

static const char *edb_mode[] = {
	"single", "multi", NULL
};

static ECMBOOL
srt_time_scan(srt_t srt, char *asrv, sr_val_t *psrv)
{
	ecm_uint64	lval;

	if (asrv != NULL && *asrv == '.') {
		psrv->lval = ecm_time();
		return ECM_TRUE;
	}
	if (ecm_sscanf(asrv, "%I64u", &lval) != 1)
		return ECM_FALSE;
	psrv->lval = lval;
	return ECM_TRUE;
}

static int
srt_xid_print(srt_t srt, char *buf, ecm_size_t *pbuflen, sr_val_t srv)
{
	char	asrvbuf[64];
	int	asrvlen;

	if ((srv.lval & ST_XID_NORMAL_MASK)) {
		ebc_ndid_t	ndid = (ebc_ndid_t)(srv.lval & ~ST_XID_NORMAL_MASK);
		asrvlen = ecm_snprintf(asrvbuf, 64, "%08x", ndid);
	}
	else {
		char	*p;

		p = asrvbuf;
		if (srv.lval == ST_XID_SELF)
			asrvlen = ecm_snprintf(p, 64, "self");
		else if (srv.lval == ST_XID_MASTER)
			asrvlen = ecm_snprintf(p, 64, "master");
		else if (srv.lval == ST_XID_CREATOR)
			asrvlen = ecm_snprintf(p, 64, "creator");
		else if (srv.lval == ST_XID_MODIFIER)
			asrvlen = ecm_snprintf(p, 64, "modifier");
		else if (srv.lval == ST_XID_ALL)
			asrvlen = ecm_snprintf(p, 64, "all");
		else
			asrvlen = ecm_snprintf(p, 64, "none");
	}

	if (*pbuflen < (ecm_size_t)asrvlen) {
		*pbuflen = asrvlen;
		return -1;
	}
	memcpy(buf, asrvbuf, asrvlen);
	return asrvlen;
}

static ECMBOOL
srt_xid_scan(srt_t srt, char *asrv, sr_val_t *psrv)
{
	ecm_uint64	lval;
	ebc_ndid_t	ndid;

	if (ecm_empty_str(asrv)) {
		ecm_get_randbytes((ecm_uint8 *)&ndid, sizeof(ndid));
		psrv->lval = ndid | ST_XID_NORMAL_MASK;
		return ECM_TRUE;
	}
	else {
		if (asrv[0] == '#') {
			asrv++;
			ebc_get_ndid(asrv, &ndid);
			lval = (ecm_uint64)ndid | ST_XID_NORMAL_MASK;
		}
		else {
			if (ecm_strcmp(asrv, "self") == 0)
				lval = ST_XID_SELF;
			else if (ecm_strcmp(asrv, "master") == 0)
				lval = ST_XID_MASTER;
			else if (ecm_strcmp(asrv, "creator") == 0)
				lval = ST_XID_CREATOR;
			else if (ecm_strcmp(asrv, "modifier") == 0)
				lval = ST_XID_MODIFIER;
			else if (ecm_strcmp(asrv, "all") == 0)
				lval = ST_XID_ALL;
			else if (ecm_strcmp(asrv, "none") == 0)
				lval = 0;
			else if (sscanf(asrv, "%08x", &ndid) == 1) {
				psrv->lval = ndid | ST_XID_NORMAL_MASK;
				return ECM_TRUE;
			}
			else
				return ECM_FALSE;
		}
		psrv->lval = lval;
		return ECM_TRUE;
	}
}

static int
srt_perm_print(srt_t srt, char *buf, ecm_size_t *pbuflen, sr_val_t srv)
{
	ecm_uint32	perm = srv.ival;
	ecm_size_t	asrvlen;
	char	permbuf[16], *p = permbuf;

	if (perm & EDB_USER_READ)
		*p++ = 'r';
	if (perm & EDB_USER_WRITE)
		*p++ = 'w';
	*p++ = ':';
	if (perm & EDB_GROUP_READ)
		*p++ = 'r';
	if (perm & EDB_GROUP_WRITE)
		*p++ = 'w';
	*p++ = ':';
	if (perm & EDB_OTHER_READ)
		*p++ = 'r';
	if (perm & EDB_OTHER_WRITE)
		*p++ = 'w';
	asrvlen = (ecm_size_t)(p - permbuf);
	if (*pbuflen < asrvlen) {
		*pbuflen = asrvlen;
		return -1;
	}
	memcpy(buf, permbuf, asrvlen);
	return asrvlen;
}

static ECMBOOL
srt_perm_scan(srt_t srt, char *asrv, sr_val_t *psrv)
{
	char	*p = asrv;
	ecm_uint32	perm = 0;

	if (*p == 'r') {
		perm += EDB_USER_READ;
		p++;
	}
	if (*p == 'w') {
		perm += EDB_USER_WRITE;
		p++;
	}
	if (*p != ':')
		return ECM_FALSE;
	p++;
	if (*p == 'r') {
		perm += EDB_GROUP_READ;
		p++;
	}
	if (*p == 'w') {
		perm += EDB_GROUP_WRITE;
		p++;
	}
	if (*p != ':')
		return ECM_FALSE;
	p++;
	if (*p == 'r') {
		perm += EDB_OTHER_READ;
		p++;
	}
	if (*p == 'w')
		perm += EDB_OTHER_WRITE;
	psrv->ival = perm;
	return ECM_TRUE;
}

static sr_parser_t	time_parser = {
	NULL, srt_time_scan
};

static sr_parser_t	xid_parser = {
	srt_xid_print, srt_xid_scan
};

static sr_parser_t	perm_parser = {
	srt_perm_print, srt_perm_scan
};

static sr_parser_t	path_parser = {
	NULL, NULL
};

static sr_parser_t	file_parser = {
	NULL, NULL
};

ECMBOOL
edb_type_initialize(void)
{
	static ECMBOOL	initialized = ECM_FALSE;

	if (initialized)
		return ECM_TRUE;

	ST_EDBFIELD = sr_enumtype_add("edbfield", edb_fields, ECM_FALSE, ST_NULL, ST_NULL);
	ST_ATTR_UPDATE = sr_enumtype_add("attr_update", attr_update, ECM_FALSE, ST_NULL, ST_NULL);
	ST_ATTR_FETCH = sr_enumtype_add("attr_fetch", attr_fetch, ECM_FALSE, ST_NULL, ST_NULL);
	ST_ATTR_SYSTEM = sr_enumtype_add("attr_system", attr_system, ECM_TRUE, ST_NULL, ST_NULL);

	ST_RUN = sr_enumtype_add("run", runs, ECM_FALSE, ST_NULL, ST_NULL);
	ST_STATUS = sr_enumtype_add("status", status, ECM_FALSE, ST_NULL, ST_NULL);
	ST_MODE = sr_enumtype_add("mode", edb_mode, ECM_FALSE, ST_NULL, ST_NULL);
	ST_TIME = sr_type_add(SR_BT_LL, "time", NULL, &time_parser);
	ST_XID = sr_type_add(SR_BT_LL, "xid", NULL, &xid_parser);
	ST_OWNER = sr_type_add(SR_BT_LL, "owner", NULL, &xid_parser);

	ST_PATH = sr_type_add(SR_BT_STR, "path", NULL, &path_parser);
	ST_FILE = sr_type_add(SR_BT_DIR, "file", NULL, &file_parser);
	ST_MFILE = sr_type_add(SR_BT_DIR, "mfile", NULL, NULL);

	ST_DIMAGE = sr_type_add(SR_BT_DIR, "dimage", NULL, NULL);

	ST_PERM = sr_type_add(SR_BT_INT, "perm", NULL, &perm_parser);

	initialized = ECM_TRUE;
	return ECM_TRUE;
}
